/*-----------------------------------------------------------------------------
    
    Copyright (C) 2005 T2-Design Corp. All rights reserved.
    
    File: obj_matrixbox.c
    
    Content: 
    
    History: 
    2006/1/11 by eric
        Inherited from M3328C code.
-----------------------------------------------------------------------------*/
#include <sys_config.h>
#include <api/libosd/osd_lib.h>
#include "osd_lib_internal.h"

//---------------------------- PRIVATE VARIABLES ----------------------------//
//---------------------------- PRIVATE FUNCTIONS ----------------------------//
static UINT8 GetShowIndex(PMATRIX_BOX mb, UINT16 nPos)
{
	UINT8 bAttr = C_ATTR_ACTIVE;
	UINT8 sty = 0;
	POBJECT_HEAD pObj = &mb->Head;	
	PMATRIX_BOX_NODE pNode = (PMATRIX_BOX_NODE)mb->pCellTable;

	if(C_ATTR_SELECT == pNode[nPos].bAttr)
		sty = pObj->style.bSelIdx;
	else if(C_ATTR_INACTIVE == pNode[nPos].bAttr)
		sty = pObj->style.bGrayIdx;//mb->bBackColor;
	else if(C_ATTR_ACTIVE == pNode[nPos].bAttr)
		sty = pObj->style.bShowIdx;

	return sty;
}

void OSD_DrawMatrixBoxItem(PMATRIX_BOX mb, UINT16 nCol, UINT16 nRow, UINT32 nCmdDraw)
{
	POBJECT_HEAD pObj = &mb->Head;
	OSD_RECT rcCell, rcText;
	UINT8 bShIdx, bMixer = 0;
	PCWINSTYLE pws;
	unsigned short  wsBuf[8];// = {0};
	UINT32 color_param, style_param;
	UINT16 nPos;
	VSCR*	pScr;// = OSD_GetVscr(&(mb->Head.frame),OSD_GET_BACK);
	UINT32 	draw_type = OSD_GetDrawType(nCmdDraw);
	UINT32	update_type = OSD_GetUpdateType(nCmdDraw);	

	nPos = nRow * mb->nCol + nCol;

	// Get Show Index
	bShIdx = GetShowIndex(mb, nPos);
	if(mb->nCount && (nPos == mb->nPos))
	{
		if(draw_type == C_DRAW_TYPE_HIGHLIGHT)
			bShIdx = pObj->style.bHLIdx;
		else if(draw_type == C_DRAW_TYPE_SELECT)
			bShIdx = pObj->style.bSelIdx;
	}	
	pws = g_osd_rsc_info.osd_get_win_style(bShIdx);
	
	// Get Matrix Cell
	OSD_CopyRect(&rcCell, &mb->Head.frame);
	rcCell.uLeft += nCol * (rcCell.uWidth + mb->bIntervalX);
	rcCell.uTop += nRow * (rcCell.uHeight + mb->bIntervalY);
 	//pScr = OSD_GetVscr(&rcCell,OSD_GET_BACK);
	//    if(PROC_PASS != OSD_SIGNAL(pCtrl, EVN_PRE_DRAW, bShIdx, &rcCell))
	//        return;

	if(nPos >= mb->nCount)
	{
	//        if(MATRIX_NO_PADDING != MATRIX_PADDING_MODE(pCtrl->bStyle))
	//            OSD_DrawTexture(&rcCell, bShIdx, NULL, 0, pScr);
		return;
	}

	pScr = OSD_DrawObjectFrame(&rcCell, bShIdx);
	pScr->updatePending = 1;

//    color_param = MAKE_COLOR_PARAM(pws->dwFgIdx, pws->dwBgIdx, 0, 0);
//    style_param = MAKE_FRAME_PARAM(pCtrl->Head.bFont, 0, DT_CENTER|DT_VCENTER, 0);
	OSD_CopyRect(&rcText, &rcCell);
	rcText.uLeft += mb->bIntervalTl;
	rcText.uTop += mb->bIntervalTt;
	rcText.uWidth -= mb->bIntervalTl; // not *2
//    if(OSD_DrawTexture(&rcCell, bShIdx, &rcText, style_param, pScr))
//        bMixer = DT_MIXER;
	UINT16* pText;
	UINT8 ctype = mb->bCellType;
	
	if(ctype & MATRIX_TYPE_NUMBER)
	{
		ComInt2UniStr(wsBuf, ((PMATRIX_BOX_NODE)(mb->pCellTable))[nPos].num, 0);
		pText = wsBuf;
		OSD_DrawText(&rcText, (UINT8*)pText, pws->wFgIdx, mb->bAssignType, pObj->bFont, pScr);
	}
	else if(ctype & MATRIX_TYPE_BITMAP)
	{
		OBJECTINFO obj;
		OSD_RECT rcIcon;		
		OSD_CopyRect(&rcIcon, &rcCell);
		rcIcon.uLeft += mb->bIntervalIl;
		rcIcon.uTop += mb->bIntervalIt;
		rcIcon.uWidth -= (mb->bIntervalIl * 2);
		rcIcon.uHeight -= (mb->bIntervalIt * 2);
		g_osd_rsc_info.osd_get_obj_info(LIB_ICON, ((PMATRIX_BOX_NODE)(mb->pCellTable))[nPos].num, &obj);
		if(obj.m_objAttr.m_wActualWidth < rcIcon.uWidth)
		{
			if(GET_HALIGN(mb->bAssignType) == C_ALIGN_CENTER)
				rcIcon.uLeft += ((rcIcon.uWidth - obj.m_objAttr.m_wActualWidth) / 2);
			else if(GET_HALIGN(mb->bAssignType) == C_ALIGN_RIGHT)
				rcIcon.uLeft += (rcIcon.uWidth - obj.m_objAttr.m_wActualWidth);
		}
		if(obj.m_objAttr.m_wHeight < rcIcon.uHeight)
		{
			if(GET_VALIGN(mb->bAssignType) == C_ALIGN_VCENTER)
				rcIcon.uTop += ((rcIcon.uHeight - obj.m_objAttr.m_wHeight) / 2);
			else if(GET_VALIGN(mb->bAssignType) == C_ALIGN_BOTTOM)
				rcIcon.uTop += (rcIcon.uHeight - obj.m_objAttr.m_wHeight);
		}
		OSD_DrawPicture(rcIcon.uLeft, rcIcon.uTop, ((PMATRIX_BOX_NODE)(mb->pCellTable))[nPos].num, LIB_ICON, pws->wFgIdx, pScr);
	}

	if(ctype & MATRIX_TYPE_STRID)
	{
		pText = (UINT16*)OSD_GetUnicodeString(((PMATRIX_BOX_NODE)(mb->pCellTable))[nPos].str);
		OSD_DrawText(&rcText, (UINT8*)pText, pws->wFgIdx, mb->bAssignType, pObj->bFont, pScr);
	}
	else if(ctype & MATRIX_TYPE_WCHAR)
	{
		pText =(UINT16*) (((PMATRIX_BOX_NODE)(mb->pCellTable))[nPos].str);
		OSD_DrawText(&rcText, (UINT8*)pText, pws->wFgIdx, mb->bAssignType, pObj->bFont, pScr);
	}

}

BOOL CheckCell(PMATRIX_BOX m, UINT16 nPos)
{
	if(nPos >= m->nCount)
		return FALSE;

	PMATRIX_BOX_NODE pNode = (PMATRIX_BOX_NODE)m->pCellTable;
	return (C_ATTR_INACTIVE!= pNode[nPos].bAttr);// && 	C_ATTR_DISABLE != pNode[nPos].bAttr);
}

static PRESULT NotifyCursorEvent(PMATRIX_BOX mb, UINT16 nPos)
{
	UINT16 nOldPos;
	UINT16 nCol, nRow;
	PRESULT Result;

	nOldPos = mb->nPos;
	Result = OSD_SIGNAL((POBJECT_HEAD)mb, EVN_ITEM_PRE_CHANGE, nOldPos, nPos);
	if(Result != PROC_PASS)
		return Result;
		
	mb->nPos = nPos;
	OSD_GetMtrxBoxCellLocation(mb, nOldPos, &nCol, &nRow);	
	OSD_DrawMatrixBoxItem(mb, nCol, nRow, C_UPDATE_FOCUS);
	OSD_GetMtrxBoxCellLocation(mb, nPos, &nCol, &nRow);		
	OSD_DrawMatrixBoxItem(mb, nCol, nRow, C_UPDATE_FOCUS);
	OSD_TrackObject((POBJECT_HEAD)mb, C_UPDATE_CONTENT);	
	OSD_SIGNAL((POBJECT_HEAD)mb, EVN_ITEM_POST_CHANGE, nPos, nOldPos);

	return Result;
}

//---------------------------- PUBLIC FUNCTIONS -----------------------------//
void OSD_GetMtrxBoxCellLocation(PMATRIX_BOX m, UINT16 nPos, UINT16 *pCol, UINT16 *pRow)
{
	*pCol = nPos % m->nCol;
	*pRow = nPos / m->nCol;
}

void OSD_DrawMatrixBoxCell(PMATRIX_BOX mb, UINT8 bStyleIdx, UINT32 nCmdDraw)
{
	UINT16 i, j;
	UINT32 update_type;
	UINT32	nSubCmdDraw;	
	//VSCR*	pScr = OSD_GetVscr(&(mb->Head.frame),OSD_GET_BACK);

//	pScr = OSD_DrawObjectFrame(&mb->Head.frame, bStyleIdx);
	nSubCmdDraw = nCmdDraw;	
	update_type = OSD_GetUpdateType(nCmdDraw);
	
	if(C_UPDATE_CURSOR == update_type)
	{
		OSD_GetMtrxBoxCellLocation(mb, mb->nPos, &i, &j);
		OSD_DrawMatrixBoxItem(mb, i, j, nSubCmdDraw);
	}
	else
	{
		for(i=0; i<mb->nRow; i++)
		{
			for(j=0; j<mb->nCol; j++)
				OSD_DrawMatrixBoxItem(mb, j, i, nSubCmdDraw);
		}
	}
}

PRESULT OSD_ShiftMatrixBoxSelHor(PMATRIX_BOX m, short sShiftX)
{
	UINT16 nCol, nRow;
	UINT16 nPos;
	UINT8 bMode = MATRIX_ROW_MODE(m->bStyle);
	BOOL fUnderFlow, fOverFlow;

	OSD_GetMtrxBoxCellLocation(m, m->nPos, &nCol, &nRow);
	while(1)
	{
		fUnderFlow = (sShiftX > 0) && (nCol == (m->nCol - 1));
		fOverFlow = (sShiftX < 0) && !nCol;
		nCol = (nCol + sShiftX + m->nCol) % m->nCol;
		nPos = nRow * m->nCol + nCol;
		if(MATRIX_ROW_STAY == bMode)
		{
			if(fUnderFlow || fOverFlow || nPos >= m->nCount)
				return PROC_LOOP;
		}
		else if(MATRIX_ROW_WRAP == bMode)
		{
			if(fUnderFlow)
			{
				//nCol = m->nCol - 1;
				nRow = (nRow + 1 + m->nRow) % m->nRow;
			}
			else if(fOverFlow)
			{
				//nCol = 0;
				nRow = (nRow - 1 + m->nRow) % m->nRow;
			}
			nPos = nRow * m->nCol + nCol;
		}
		if(nPos == m->nPos)
			return PROC_LOOP;
		if(CheckCell(m, nPos))
			break;
	}
	return NotifyCursorEvent(m, nPos);
}

PRESULT OSD_ShiftMatrixBoxSelVer(PMATRIX_BOX m, short sShiftY)
{
	UINT16 nCol, nRow;
	UINT16 nPos;
	UINT8 bMode = MATRIX_COL_MODE(m->bStyle);
	BOOL fUnderFlow, fOverFlow;

	OSD_GetMtrxBoxCellLocation(m, m->nPos, &nCol, &nRow);
	while(1)
	{
		fUnderFlow = (sShiftY > 0) && (nRow == (m->nRow - 1));
		fOverFlow = (sShiftY < 0) && !nRow;
		nRow = (nRow + sShiftY + m->nRow) % m->nRow;
		nPos = nRow * m->nCol + nCol;
		if(MATRIX_COL_STAY == bMode)
		{
			if(fUnderFlow || fOverFlow || nPos >= m->nCount)
				return PROC_LOOP;
		}
		if(nPos == m->nPos)
			return PROC_LOOP;
		if(CheckCell(m, nPos))
			break;
	}
	return NotifyCursorEvent(m, nPos);
}

void OSD_SetMtrxboxCount(PMATRIX_BOX m, UINT16 count, UINT16 row, UINT16 col)
{
	if(row * col >= count)
	{
		m->nCount = count;
		m->nRow = row;
		m->nCol = col;
	}
}

UINT16 OSD_GetMtrxboxCurPos(PMATRIX_BOX m)
{
	return m->nPos;
}

void OSD_SetMtrxboxCurPos(PMATRIX_BOX m, UINT16 nPos)
{
	if(nPos < m->nCount)
	{
		m->nPos = nPos;
	}
}

VACTION OSD_MatrixboxKeyMap(POBJECT_HEAD pObj, UINT32 vkey)
{
	VACTION		Vact = VACT_PASS;
	MATRIX_BOX	*mb = (MATRIX_BOX *)pObj;

	switch(vkey)
	{
		case V_KEY_UP:
			Vact = VACT_CURSOR_UP;
			break;
		case V_KEY_DOWN:
			Vact = VACT_CURSOR_DOWN;
			break;
		case V_KEY_LEFT:
			Vact = VACT_CURSOR_LEFT;
			break;
		case V_KEY_RIGHT:
			Vact = VACT_CURSOR_RIGHT;
			break;
		case V_KEY_ENTER:
			Vact = VACT_ENTER;
			break;
		default:
			Vact = VACT_PASS;
	}
	return Vact;
}

static PRESULT OSD_MatrixboxShift(PMATRIX_BOX mb, UINT8 Action)
{
    if(MATRIX_STYLE_MODE(mb->bStyle) == MATRIX_STYLE_5A1)
    {
        if( Action == VACT_CURSOR_UP)
        {
            if((mb->nPos == 2)||(mb->nPos == 3))
                return PROC_LOOP;
            else if((mb->nPos == 0)||(mb->nPos == 1))
            {
                OSD_ShiftMatrixBoxSelHor(mb, -1);
                return PROC_LOOP;
            }    
            else if(mb->nPos == 4)
                NotifyCursorEvent(mb, 1);
            return PROC_LOOP;
        }
        else if( Action == VACT_CURSOR_DOWN)
        {
            if((mb->nPos == 2)||(mb->nPos == 3))
                return PROC_LOOP;
            else if((mb->nPos == 0)||(mb->nPos == 4))
            {
			    OSD_ShiftMatrixBoxSelHor(mb, 1);
			    return PROC_LOOP;
			}   
            else if(mb->nPos == 1)
                NotifyCursorEvent(mb, 4);
            return PROC_LOOP;
        }
    }
    
    if(MATRIX_STYLE_MODE(mb->bStyle) == MATRIX_STYLE_12A1)
    {
        if( Action == VACT_CURSOR_UP)
        {
            if(mb->nPos == 0)
            {
                if(mb->nCount >= 9)
                    NotifyCursorEvent(mb, 8);
                else if(mb->nCount >= 7)    
                    NotifyCursorEvent(mb, 6);
                else if(mb->nCount >= 5)
                    NotifyCursorEvent(mb, 4);
                return PROC_LOOP;
            }
            if(mb->nPos == 4)
            {
                NotifyCursorEvent(mb, 0);
                return PROC_LOOP;
            }
            if((mb->nPos == 6)||(mb->nPos == 8))
            {
                NotifyCursorEvent(mb, mb->nPos-2);
                return PROC_LOOP;
            }
            if(mb->nPos == 3)
            {
                if(mb->nCount >= 12)
                    NotifyCursorEvent(mb, 11);
                else if(mb->nCount >= 8)    
                    NotifyCursorEvent(mb, 7);
                else if(mb->nCount >= 6)
                    NotifyCursorEvent(mb, 5);
                return PROC_LOOP;
            }
            if((mb->nPos == 5)||(mb->nPos == 7))
            {
                NotifyCursorEvent(mb, mb->nPos-2);
                return PROC_LOOP;
            }
            if(mb->nPos == 11)
            {
                NotifyCursorEvent(mb, 7);
                return PROC_LOOP;
            }
            return PROC_LOOP;
        }
        else if( Action == VACT_CURSOR_DOWN)
        {
            if(mb->nPos == 0)
            {
                if(mb->nCount >= 5)
                    NotifyCursorEvent(mb, 4);
                return PROC_LOOP;
            }
            if(mb->nPos == 4)
            {
                if(mb->nCount >= 7)
                    NotifyCursorEvent(mb, 6);
                return PROC_LOOP;
            }
            if(mb->nPos == 6)
            {
                if(mb->nCount >= 9)
                    NotifyCursorEvent(mb, 8);
                return PROC_LOOP;
            }
            if(mb->nPos == 8)
            {
                NotifyCursorEvent(mb, 0);
                return PROC_LOOP;
            }
            if(mb->nPos == 3)
            {
                if(mb->nCount >= 6)
                    NotifyCursorEvent(mb, 5);
                return PROC_LOOP;
            }
            if(mb->nPos == 5)
            {
                if(mb->nCount >= 8)
                    NotifyCursorEvent(mb, 7);
                return PROC_LOOP;
            }
            if(mb->nPos == 7)
            {
                if(mb->nCount >= 12)    
                    NotifyCursorEvent(mb, 11);
                return PROC_LOOP;
            }
            return PROC_LOOP;
        }
    }
    return PROC_PASS;
    
}
PRESULT OSD_MatrixboxProc(POBJECT_HEAD pObjHead, UINT32 msg_type, UINT32 msg,UINT32 param1)
{
	PRESULT Result = PROC_PASS;
	OBJECT_HEAD*	pObject;
	MATRIX_BOX	*m = (MATRIX_BOX*)pObjHead;
    
	if(msg_type == MSG_TYPE_KEY)
	{
		VACTION Action;
		UINT32 vkey;
		//UINT32 hkey = msgCode;
		BOOL bContinue;
		Result = OSD_ObjCommonProc(pObjHead, msg, param1, &vkey, &Action, &bContinue);
		if(Result != PROC_PASS)
			return Result;

		switch (Action)
		{
//			case VACT_PASS:
//				Result = PROC_PASS;
//				break;
			case VACT_CURSOR_UP:
			    if(OSD_MatrixboxShift(m, VACT_CURSOR_UP) == PROC_LOOP)
			    {
			        Result = PROC_LOOP;
			        break;
			    }
				Result = OSD_ShiftMatrixBoxSelVer(m, -1);
				break;
			case VACT_CURSOR_DOWN:
			    if(OSD_MatrixboxShift(m, VACT_CURSOR_DOWN) == PROC_LOOP)
			    {
			        Result = PROC_LOOP;
			        break;
			    }
				Result= OSD_ShiftMatrixBoxSelVer(m, 1);
				break;
			case VACT_CURSOR_LEFT:
				Result = OSD_ShiftMatrixBoxSelHor(m, -1);
				break;
			case VACT_CURSOR_RIGHT:
				Result= OSD_ShiftMatrixBoxSelHor(m, 1);
				break;
CLOSE_OBJECT:
		    	case VACT_CLOSE:
		    		Result = OSD_ObjClose(pObjHead, C_CLOSE_CLRBACK_FLG);
		    		break;
			default:
				Result = OSD_SIGNAL(pObjHead, EVN_UNKNOWN_ACTION, (Action<<16) | vkey, param1);
				break;
		}
	}
	else// if(msg_type==MSG_TYPE_EVNT)
		Result = OSD_SIGNAL(pObjHead, msg_type, msg, param1);

CHECK_LEAVE:
	if(!(EVN_PRE_OPEN == msg_type))
		CHECK_LEAVE_RETURN(Result,pObjHead);

EXIT:	
	return Result;
}

